package com.tanhua.server.service;

import com.tanhua.commons.SoulConstants;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.*;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.mongo.*;
import com.tanhua.model.vo.OptionVo;
import com.tanhua.model.vo.QuestionVo;
import com.tanhua.model.vo.QuestionnaireVO;
import com.tanhua.model.vo.ReportVo;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.beans.BeanUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 测灵魂
 */
@Service
public class TestSoulService {

    @DubboReference
    private QuestionnaireApi questionnaireApi;

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private OptionApi optionApi;

    @DubboReference
    private ReportApi reportApi;

    @DubboReference
    private DimensionsApi dimensionsApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private TestSoulApi testSoulApi;

    @Autowired
    private SimilarYouService similarYouService;

    /**
     * 测灵魂-问卷列表
     * @return
     */
    public List<QuestionnaireVO> testSoul() {
        // 定义boolean用来判断问卷是否要上锁，true为不上锁
        boolean b = true;

        // 查出所有的问卷列表
        List<Questionnaire> questionnaireList = questionnaireApi.findAll();
        List<QuestionnaireVO> list = new LinkedList<>();

        for (Questionnaire questionnaire : questionnaireList) {
            String questionnaireId = questionnaire.getId().toHexString();

            // 查出该问卷列表的所有试题
            List<Question> questionList = questionApi.findByQuestionnaireId(questionnaireId);
            List<QuestionVo> questionVoList = new LinkedList<>();

            for (Question question : questionList) {
                QuestionVo questionVo = new QuestionVo();
                BeanUtils.copyProperties(question, questionVo);
                questionVo.setId(question.getId().toHexString());

                // 查出该试题下的所有选项
                List<Option> optionList = optionApi.findByQuestionId(question.getId().toHexString());
                List<OptionVo> optionVoList = new LinkedList<>();
                for (Option option : optionList) {
                    OptionVo optionVo = new OptionVo();
                    BeanUtils.copyProperties(option, optionVo);
                    optionVo.setId(option.getId().toHexString());
                    optionVoList.add(optionVo);
                }
                questionVo.setOptions(optionVoList);
                questionVoList.add(questionVo);
            }

            QuestionnaireVO questionnaireVO = QuestionnaireVO.init(questionnaire, questionVoList);

            // 判断该问卷是否需要上锁
            if (b) {// 不上锁
                questionnaireVO.setIsLock(0);
                b = false;
            } else {
                questionnaireVO.setIsLock(1);
            }

            // 判断该用户是否做过该问卷
            Long userId = UserHolder.getUserId();
            Report report = reportApi.findByUserIdAndQuestionnaireId(UserHolder.getUserId(), questionnaireId);
            if (null != report) {
                questionnaireVO.setReportId(report.getId().toHexString());
                b = true;
            }

            list.add(questionnaireVO);
        }

        return list;
    }



    /**
     * 测灵魂—提交问卷
     * @param answers
     * @return
     */
    public String submitTest(List<Answer> answers) {
        //获得用户id
        Long userId = UserHolder.getUserId();
        //1:根据选项id查询option选项
        List<ObjectId> optionIds = answers.stream().map(answer -> { return new ObjectId(answer.getOptionId());}).collect(Collectors.toList());
        List<Option> optionList= optionApi.findByIds(optionIds);
            //计算总分
        Double scores=0.0;
        for (Option option : optionList) {
            scores+=option.getScore();
        }
        //2:根据总分获得人格类型
        String conclusion=SoulConstants.getConclusionAndCover(scores).get("conclusion");
        String cover=SoulConstants.getConclusionAndCover(scores).get("cover");


        //根据题目id获取问卷对象
        Question question = questionApi.findById(answers.get(0).getQuestionId());
        Questionnaire questionnaire = questionnaireApi.findById(question.getQuestionnaireId().toHexString());

        //根据userid获取用户性别
        UserInfo currentUser = userInfoApi.getById(userId);

        //3:添加&&修改 评分报告
        Report report = new Report();
        report.setUserId(userId);
        report.setConclusion(conclusion);
        report.setQuestionnaireId(questionnaire.getId());
        report.setScore(scores);
        report.setCover(cover);
        report.setLevel(questionnaire.getLevel());
        report.setCreated(System.currentTimeMillis());
        report.setUpdated(System.currentTimeMillis());
        report.setGender(currentUser.getGender());

        report= reportApi.addAndUpdateReport(report);
        String reportId =report.getId().toHexString();

        //4:添加&&修改 维度
        List<Double> doubles = optionApi.findScore(optionIds);
        List<Dimension> dimensionList = init(doubles);
        dimensionsApi.addAndUpdateDimension(dimensionList);

        //5:添加&修改 等级解锁
        //判断是否存在用户的等级数据
        boolean flag = stringRedisTemplate.hasKey(SoulConstants.QUESTIONNAIRE_LEVEL + userId);
        if (flag) {
            //存在：则先判断reids储存的等级是否大于提交试卷的等级
            Integer redisLevel = Integer.valueOf(stringRedisTemplate.opsForValue().get(SoulConstants.QUESTIONNAIRE_LEVEL + userId));//redis储存的用户等级
            Integer thisLevel = Integer.valueOf(questionnaire.getLevel().toString());//本套试卷的用户等级
            if (redisLevel<thisLevel){
                stringRedisTemplate.delete(SoulConstants.QUESTIONNAIRE_LEVEL + userId);
                stringRedisTemplate.opsForValue().set(SoulConstants.QUESTIONNAIRE_LEVEL + userId,questionnaire.getLevel().toString());
            }
        }else {
            //储存用户的 等级数据到redis
            stringRedisTemplate.opsForValue().set(SoulConstants.QUESTIONNAIRE_LEVEL + userId,questionnaire.getLevel().toString());
        }


        return reportId;
    }

    public ReportVo findReportResult(String id) {
        //根据报告ID查询报告
        Report report = testSoulApi.findResult(id);

        ReportVo reportVo = new ReportVo();
        BeanUtils.copyProperties(report,reportVo);

        //设置报告维度
        ObjectId reportid = new ObjectId(id);
        reportVo.setDimensions(dimensionsApi.findDimensionsList(reportid));

        //设置报告相似者
        List<SimilarYou> similarYouList =  similarYouService.findSimilarYouList(report.getUserId());
        reportVo.setSimilarYou(similarYouList);
        return reportVo;
    }

    /**
     * 维度算法
     * @param values
     * @return
     */
    private List<Dimension> init(List<Double> values) {
        Map<Double,Integer> map = new HashMap<>();
        for (Double value : values) {
            if (map.get(value) == null) {
                map.put(value, 1);
            }else {
                map.put(value, map.get(value) + 1);
            }
        }

        int s1 = map.get(1) == null ? 0 : map.get(1);
        int s2 = map.get(2) == null ? 0 : map.get(2);
        int s3 = map.get(3) == null ? 0 : map.get(3);
        int s4 = map.get(4) == null ? 0 : map.get(4);
        int s5 = map.get(5) == null ? 0 : map.get(5);
        int s6 = map.get(6) == null ? 0 : map.get(6);
        int s7 = map.get(7) == null ? 0 : map.get(7);

        Dimension dimension1 = new Dimension();
        dimension1.setKey("外向");
        int v1 = s1 * 4 + s2 * 5 + s3 * 6 + s4 * 7 + s5 * 8 + s6 * 9 + s7 * 10;
        dimension1.setValue(v1 + "");
        Dimension dimension2 = new Dimension();
        dimension2.setKey("判断");
        int v2 = s1 * 10 + s2 * 4 + s3 * 5 + s4 * 6 + s5 * 7 + s6 * 8 + s7 * 9;
        dimension2.setValue(v2 + "");
        Dimension dimension3 = new Dimension();
        dimension3.setKey("抽象");
        int v3 = s1 * 9 + s2 * 10 + s3 * 4 + s4 * 5 + s5 * 6 + s6 * 7 + s7 * 8;
        dimension3.setValue(v3 + "");
        Dimension dimension4 = new Dimension();
        dimension4.setKey("理性");
        int v4 = s1 * 8 + s2 * 9 + s3 * 10 + s4 * 4 + s5 * 5 + s6 * 6 + s7 * 7;
        dimension4.setValue(v4 + "");

        return Arrays.asList(dimension1, dimension2,dimension3,dimension4);
    }
}
